#include "wrap.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
void perr_exit(const char *s)
{
        perror(s);
        exit(-1);
}
void printAddr(const char*s,struct sockaddr_in* addr)
{
        char ip[BUFSIZ];
        printf("%s %s:%d\n",s,
                inet_ntop(AF_INET,&addr->sin_addr.s_addr,ip,sizeof(ip)),
                ntohs(addr->sin_port));
}
int Socket(int family, int type, int protocol)
{
        int n;
        if( (n = socket(family,type,protocol)) < 0 ){
                perr_exit("socket error");
        }
        return n;
}
int Bind(int fd, const struct sockaddr* addr, socklen_t addrlen)
{
        int n;
        if( (n = bind(fd, addr, addrlen)) < 0 ){
                perr_exit("bind error");
        }
        return n;
}
int Connect(int fd, const struct sockaddr* addr, socklen_t addrlen)
{
        int n;
        n = connect(fd, addr, addrlen);
        if(n < 0){
                perr_exit("connect error");
        }
        return n;
}
int Listen(int fd, int backlog)
{
        int n;
        if((n = listen(fd, backlog)) < 0){
                perr_exit("listen error");
        }
        return n;
}
int Accept(int fd, struct sockaddr* addr, socklen_t *addrlen)
{
        int n;
again:
        if( (n = accept(fd, addr, addrlen)) < 0 ){
                //ECONNABORTED 发生在重传(一定次数) 失败后,强制关闭套接字
                //EINTR 进程被信号中断       因为信号的优先级高会打断accept,使得accept暂停了
                if( (errno == ECONNABORTED) || (errno == EINTR) ){
                        goto again;
                }else{
                        perr_exit("accept error");
                }
        }
        return n;
}
ssize_t Read(int fd, void* ptr, size_t nbytes)
{
        ssize_t n;
again:
        if( (n = read(fd, ptr, nbytes)) == -1){
                if(errno == EINTR){ //read是阻塞的,如果被信号中断了,从这里继续执行
                        goto again;
                }else{
                        return -1;
                }
        }
        return n;
}
ssize_t Write(int fd, const void* ptr, size_t nbytes)
{
        ssize_t n;
again:
        if( (n = write(fd,ptr,nbytes)) == -1){
                if(errno == EINTR){ //write是阻塞的,如果被信号中断了,从这里继续执行
                //write什么时候阻塞的 滑动窗口满了就会阻塞
                        goto again;
                }else{
                        return -1;
                }
        }
        return n;
}
int Close(int fd)
{
        int n;
        if( (n = close(fd)) == -1 ){
                perr_exit("close error");
        }
        return n;
}
/**
 *参数三: 应该读取的字节数
 *socket 4096 readn(cfd, buf, 4096) nleft = 4096-1500 
 */
ssize_t Readn(int fd, void* vptr, size_t n)
{
        size_t nleft; //usigned int 剩余未读取的字节数
        ssize_t nread; //int 实际读到的字节数
        char *ptr;

        ptr = vptr;
        nleft = n; //n 未读取字节数

        while (nleft > 0){
                if((nread = read(fd, ptr, nleft)) < 0){
                        if(errno == EINTR){
                                nread = 0;
                        }else{
                                return -1;
                        }
                }else if(nread == 0){
                        break;
                }
                nleft -= nread;
                ptr += nread;
        }
        return n - nleft;
}
ssize_t Writen(int fd, const void* vptr, size_t n)
{
        size_t nleft;
        ssize_t nwritten;
        const char *ptr;

        ptr = vptr;
        nleft = n;
        while (nleft > 0){
                if( (nwritten = write(fd,ptr,nleft)) <= 0){
                        if(nwritten < 0 && errno == EINTR){
                                nwritten = 0;
                        }else{
                                return -1;
                        }
                }
                nleft -= nwritten;
                ptr += nwritten;
        }
        return n;
}
static ssize_t my_read(int fd, char* ptr)
{
        static int read_cnt;
        static char* read_ptr;
        static char read_buf[100];

        if(read_cnt <= 0){
again:
                if((read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0){
                        if(errno = EINTR){
                                goto again;
                        }
                        return -1;
                }else if(read_cnt == 0){
                        return 0;
                }
                read_ptr = read_buf;
        }
        read_cnt--;
        *ptr = *read_ptr++;
        return 1;
}
/*readline --- fgets*/
//传出参数
ssize_t Readline(int fd, void* vptr, size_t maxlen)
{
        ssize_t n, rc;
        char c, *ptr;
        ptr = vptr;

        for ( n = 1; n < maxlen; n++){
                if((rc = my_read(fd,&c)) == 1){
                        *ptr++ = c;
                        if(c == '\n'){
                                break;
                        }
                }else if(rc == 0){
                        *ptr = 0;
                        return n-1;
                }else{
                        return -1;
                }
        }
        *ptr = 0;
        return n;
}